/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * GameLoader.java
 *
 * Created on May 2, 2011, 1:59:12 PM
 */
package GUI.GameLoadWindowPackage;

import GameServer.ServerService;
import Monopol.MonopolExceptions.MonopolErrors;
import Utils.GameDetails;
import Utils.LoadInfo;
import Utils.Utils;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

/**
 * @author Avia Tam
 * @author Assaf Miron
 *
 */
public class GameLoader extends JFrame {
    private ListSelectionModel listSelectionModel;
    private LoadInfo[] arrPlayers = new LoadInfo[6];
    private Boolean finished = false;
    private Integer playerID;
    private Boolean bAutoDice;
    private Timer gamesRefreshTimer;
    
    private CountDownLatch closeSignal;

    /** Creates new form GameLoader */
    public GameLoader() {
	// Set the OS Default Look and Feel
	Utils.setLookAndFeel();
	// Initialize the Rest of the Components and Add them to the Frame
	initComponents();
	// Centering the window
        this.setBounds(Utils.posCenterScreen(getWidth(), getHeight()));
	setLocationRelativeTo(null);
	// Start a Refresh Task for the Games
        startRefreshTask();
	// Pack the Frame with the Desired Width and Heigth
	pack();
    }


    /**
     * Show this Frame
     */
    public Boolean showLoadWindow(CountDownLatch cntDown) {
	if(closeSignal == null){
	    closeSignal = cntDown;
	}
            // Show the Load Window
            setVisible(true);
            // Returned only after this Frame is no longer Visible
            return finished;
    }

     private void startRefreshTask() {
//        gamesRefreshTimer = ServerService.getInstance().startPolling("Waiting Games Timer", new RefreshMonopolyGames(this), 0, 5);
    }

   private void stopRefreshTask() {
        if (gamesRefreshTimer != null) {
            gamesRefreshTimer.cancel();
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        tblGames = new javax.swing.JTable();
        btnCreate = new javax.swing.JButton();
        btnJoin = new javax.swing.JButton();
        lblHeader = new javax.swing.JLabel();
        pnlGameDetails = new javax.swing.JPanel();
        lblGameDetails = new javax.swing.JLabel();
        lblText = new javax.swing.JLabel();

        setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        setName("frmGameLoader"); // NOI18N

        tblGames.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Name", "Num. Of Players", "Num. Of Humans"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Integer.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tblGames.setColumnSelectionAllowed(true);
        tblGames.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        tblGames.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                tblGamesPropertyChange(evt);
            }
        });
        jScrollPane1.setViewportView(tblGames);
        tblGames.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);

        btnCreate.setText("Create");
        btnCreate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCreateActionPerformed(evt);
            }
        });

        btnJoin.setText("Join");
        btnJoin.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnJoinActionPerformed(evt);
            }
        });

        lblHeader.setFont(new java.awt.Font("Century", 1, 24)); // NOI18N
        lblHeader.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/icon.png"))); // NOI18N
        lblHeader.setText("Monopoly Games");

        pnlGameDetails.setBorder(new javax.swing.border.MatteBorder(null));

        lblGameDetails.setText("No Game Selected");

        javax.swing.GroupLayout pnlGameDetailsLayout = new javax.swing.GroupLayout(pnlGameDetails);
        pnlGameDetails.setLayout(pnlGameDetailsLayout);
        pnlGameDetailsLayout.setHorizontalGroup(
            pnlGameDetailsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlGameDetailsLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lblGameDetails)
                .addContainerGap(95, Short.MAX_VALUE))
        );
        pnlGameDetailsLayout.setVerticalGroup(
            pnlGameDetailsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlGameDetailsLayout.createSequentialGroup()
                .addComponent(lblGameDetails)
                .addContainerGap(175, Short.MAX_VALUE))
        );

        lblText.setFont(lblText.getFont().deriveFont(lblText.getFont().getSize()+3f));
        lblText.setText("Choose the Monopoly Game You want to Join or Create a New One.");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(34, 34, 34)
                        .addComponent(btnJoin)
                        .addGap(154, 154, 154)
                        .addComponent(btnCreate))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 340, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(10, 10, 10)
                        .addComponent(pnlGameDetails, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(130, 130, 130)
                        .addComponent(lblHeader))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(lblText)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lblHeader)
                .addGap(7, 7, 7)
                .addComponent(lblText)
                .addGap(29, 29, 29)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(pnlGameDetails, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnJoin)
                    .addComponent(btnCreate))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void tblGamesPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_tblGamesPropertyChange
    }//GEN-LAST:event_tblGamesPropertyChange

    /**
     * The Action Preformed on Join Button Click
     * @param evt
     */
    private void btnJoinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnJoinActionPerformed
        try {
            // Get the Table Model
            DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
            // Get the Selected Row
            int selectedRow = tblGames.getSelectedRow();
            // Get the Game Name from the Selected Row First Column
            String gameName = (String) model.getValueAt(selectedRow, 0);
            // Get the Game Details for the elected Game from the Server
            GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
            // Verify that the game can be joined
            if (gameDetails.getGameStatus() == null ? "Waiting" == null : gameDetails.getGameStatus().equals("Waiting")) {
                // The game has not started yet, so all the players are active and with thiere initial Money
                // Get All the Players in the Game
                ServerService.getInstance().getPlayersDetails(gameName).toArray(arrPlayers);
                
                // Hide this Window
    		this.setVisible(false);
		 // Open the Game Load Window with these Players inorder to allow the Player to Change its Details
                GameCreationPanel gameLoad = new GameCreationPanel(this, gameName, arrPlayers, (gameDetails.getTotalComputerPlayers() + gameDetails.getTotalHumanPlayers()), gameDetails.isAutomaticDiceRoll());
		// Show this Window Again
		this.setVisible(true);
                // Update the Players Array
                arrPlayers = gameLoad.getPlayersArray();
                // Get the Dice Mode
                bAutoDice = gameLoad.getAutomaticDices();
                // Join the Player to the Game in the Server
                Integer pID = ServerService.getInstance().joinPlayer(gameName, arrPlayers[arrPlayers.length - 1].getPlayerName());
                // Close the Window and Save the Players ID
                CloseWindow(pID, true);
            } else {
                throw new MonopolErrors("Can not join an Active Game.");
            }
        } catch (MonopolErrors ex) {
            Logger.getLogger(GameLoader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_btnJoinActionPerformed

    /**
     * Selects a Specific Game Row in the Game Table
     * @param gameName The Game to Select
     */
    private void selectGame(String gameName)
    {
        DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
        Integer i = 0;
        Boolean found = false;
        while(found == false && i < model.getRowCount())
        {
            if(model.getValueAt(i, 0) == gameName)
            {
                // Select the Row
               tblGames.setRowSelectionInterval(i, i);
               // We found our Game - End the Loop
               found = true;
            }
            // Increment the Counter
            i++;
        }
    }


    public void addCreateListener(ActionListener listener){
	btnCreate.addActionListener(listener);
    }

   /**
    * Updates the Parameters from the Newly Created Game
    * @param gameName The Game Name
    * @param arrNewPlayers The New Players Array
    * @param isAutoDice The Dice Roll Mode
    */
    public void updateCreatedGame(String gameName, LoadInfo[] arrNewPlayers, Boolean isAutoDice){
	try {
	    // Initialize the Variables
	    Integer humans = 0;
	    Integer computers = 0;
	    // Get the Players from the Load Window
	    arrPlayers = arrNewPlayers;
	    // Count the Humans and Computers in the Game
	    for (int i = 0; i < arrPlayers.length; i++) {
		if (arrPlayers[i].getIsHuman()) {
		    humans++;
		} else {
		    computers++;
		}
	    }

	    // Start a Game - Usually in Wating State
	    ServerService.getInstance().startGame(gameName, humans, computers, isAutoDice);

	    // Update the Games Table
	    getMonopolyGames();
	    // Select the Newly created Game
	    selectGame(gameName);
	    // Check if the Game can Start
	    CloseWindow(0, true); // Player Index is 0 because he Started the Game
	} catch (MonopolErrors ex) {
	    Logger.getLogger(GameLoader.class.getName()).log(Level.SEVERE, null, ex);
	}
    }

    /**
     * Creates a New Monopoly Game
     * @param evt
     */
    private void btnCreateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCreateActionPerformed
	 final CountDownLatch loadSignal = new CountDownLatch(1);
	// Hide this Panel
	// Create a new Game Creation Panel
	GameCreationPanel gameLoad = new GameCreationPanel(this);
	// Get the Main Panel
	JPanel createPanel = gameLoad.getMainPanel();
	// Show the Create Monopoly Game Panel
	createPanel.setVisible(true);
	this.add(createPanel);
    }//GEN-LAST:event_btnCreateActionPerformed

    /**
     * Returns the Players Array Info
     * @return Players Array Info as Array of LoadInfo
     */
    public LoadInfo[] getPlayersArray()
    {
            return arrPlayers;
    }

    /**
     * Returns the Player ID in the Game
     * @return The Players ID in the Game
     */
    public Integer getPlayerID()
    {
        if(playerID != null)
        {
            return playerID;
        }
        else
        {
            // Return an Error Integer
            return -1;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
	java.awt.EventQueue.invokeLater(new Runnable() {

	    public void run() {
		new GameLoader().setVisible(true);
	    }
	});
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnCreate;
    private javax.swing.JButton btnJoin;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JLabel lblGameDetails;
    private javax.swing.JLabel lblHeader;
    private javax.swing.JLabel lblText;
    private javax.swing.JPanel pnlGameDetails;
    private javax.swing.JTable tblGames;
    // End of variables declaration//GEN-END:variables

    /**
     * Updates the Table about the Current Games in the Server
     */
    public void getMonopolyGames() {
	String[] waitingGames = ServerService.getInstance().getWaitingMonopolyGames();
	String[] activeGames = ServerService.getInstance().getActiveMonopolyGames();
	// Check if No Waiting Games And there are Active Games
	if (waitingGames.length == 0 && activeGames.length > 0) {
	    // Enable the Join Button
	    btnJoin.setEnabled(true);
	    // Disable the Create a New Game - Working in One Active Game Only
	    btnCreate.setEnabled(false);
	    getGames(waitingGames);
	} else if (waitingGames.length > 0 && activeGames.length == 0) {
	    // Enable the Join Button
	    btnJoin.setEnabled(true);
	    // Disable the Create a New Game - Working in One Active Game Only
	    btnCreate.setEnabled(false);
	    getGames(activeGames);
	} else {
	    // No Games - Allow Create
	    btnCreate.setEnabled(true);
	    // Disable Joining A Game
	    btnJoin.setEnabled(false);
	}

    }

    /**
     * Updates the Table with Monopoly Games
     * @param monopolyGames The Monopoly Games Names String Array
     */
    private void getGames(String[] monopolyGames) {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// For Each Game in the Monopoly Games
	for (String name : monopolyGames) {
	    // Get the Game Details for the Game
	    GameDetails gameDetails = ServerService.getInstance().getGameDetails(name);
	    // Add a new Row to the Table
	    model.addRow(new Object[]{name, gameDetails.getTotalPlayers(), gameDetails.getJoinedHumans()});
	}
	// Set the New Rows
	tblGames.setModel(model);
	listSelectionModel = tblGames.getSelectionModel();
	listSelectionModel.addListSelectionListener(new TableListSelectionHandler());
	tblGames.setSelectionModel(listSelectionModel);
    }

    /**
     * Updates the Game Details in the Details Pane
     */
    protected void updateGameDetail() {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// Get the Selected Row
	int selectedRow = tblGames.getSelectedRow();
	// Get the Game Name from the Selected Row First Column
	String gameName = (String) model.getValueAt(selectedRow, 0);
	// Get the Game Details for the elected Game from the Server
	GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
	// Construct the Message
	String detailsText = gameName + "(" + gameDetails.getGameStatus().toString() + ")\n\n"
		+ "Totla Number Of Players: "
		+ Integer.toString(gameDetails.getTotalPlayers()) + "\n"
		+ "Number of Computerized Players: " + Integer.toString(gameDetails.getTotalComputerPlayers()) + "\n"
		+ "Number of Human Players (Joined Players/Total Players): " + Integer.toString(gameDetails.getJoinedHumans())
		+ "/" + Integer.toString(gameDetails.getTotalPlayers()) + "\n";
	// Check the Dice Roll Mode
	if (gameDetails.isAutomaticDiceRoll()) {
	    detailsText += "Using Automatic Dice Roll.";
	} else {
	    detailsText += "Using Manual Inserted Dice Roll.";
	}
	// Set the Text to the Game Details Label
	lblGameDetails.setText(detailsText);
    }

    /**
     * Check that the Game can Begin and if So Closes the Window
     * @param playerID The Player ID Retrieved from the Server
     * @param isFinished Is the Game Load Window has Finished its Functionality
     */
    private void CloseWindow(Integer playerID, boolean isFinished) {
        // Save the Player ID
        this.playerID = playerID;
        // Check that the Game can Start
        if(isFinished)
        {
            // Get the Selected Game Row Index
            int selectedRow = tblGames.getSelectedRow();
            // Refresh the Game Details in the Table
            getMonopolyGames();
            // Re-Select the Selected Game Row
            tblGames.setRowSelectionInterval(selectedRow, selectedRow);
            // Check that all the Required players have joined
            if(checkPosibleStart())
            {
                // Stop Refreshing the Games
                stopRefreshTask();
                // Close this Frame
                this.dispose();
		closeSignal.countDown();
            }
            else
            {
                // Waiting for other Players to Join
            }
        }
    }

    /**
     * Check the Availability of the Game to Start
     * @return True if the Game can Begin, False Otherwise
     */
    private boolean checkPosibleStart() {
        // Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// Get the Selected Row
	int selectedRow = tblGames.getSelectedRow();
	// Get the Game Name from the Selected Row First Column
	String gameName = (String) model.getValueAt(selectedRow, 0);
	// Get the Game Details for the elected Game from the Server
	GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
        if(gameDetails.getTotalHumanPlayers() == gameDetails.getJoinedHumans())
        {
            // All the Human Players Have Joined
            // The Game can Begin!
            return true;
        }
        else
        {
            // No All the Human Players have Joined
            // Waiting for other Players to Join
            return false;
        }
    }

    /**
     * Returns the Dice Mode
     * True if Using Automatic Dice Roll Mode
     * False if Using Manual Dice Roll Mode
     * @return The Automatic Dice Roll Mode
     */
    public Boolean getAutomaticDice()
    {
        return bAutoDice;
    }

    /**
     *  Table Selection Listener
     */
    class TableListSelectionHandler implements ListSelectionListener {

	public void valueChanged(ListSelectionEvent e) {
	    ListSelectionModel lsm = (ListSelectionModel) e.getSource();
	    if (!lsm.getValueIsAdjusting()) {
		updateGameDetail();
	    }
	}
    }
}
